// OnStyle
//
// Copyright (c)  Daigo Tanaka
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//
// Global variables
//
var mousex = 0;
var mousey = 0;
var grabx = 0;
var graby = 0;
var orix = 0;
var oriy = 0;
var elex = 0;
var eley = 0;
var elew = 0;
var eleh = 0;
var algor = 0;
var mode = -1; // 0:pos 1:width
var dragobj = null;
var selectedObject = null;
var container = null;
var highestZIndex = 10;
var highestZIndexForElement = 9;
var highlightedObject = null; // Need to use this to support IE
var objectInFocus = null; // Need to use this to support IE in grab()
var eventRoot = null;
var dialog = null;
var mouseOffsetX = 0;
var mouseOffsetY = 0;
var initializedOnce = false;

//
// Initializer
//
// Set default value to the root container, and ask the user to start
//document.getElementById(osRootContainerID).value = osDefaultRootID;
populateRootOptions()
//selectAll(osRootContainerID);
initializeDialog();

alert("Set the root continer ID and click \"set\" to begin.");
// ...but do not start automatically, or IE will break the layout :(
// initOnStyle(osDefaultRoot, false); 

//
// Const methods
//
function falsefunc() { return false; } // used to block cascading events

function browserSupported()
{
  return true;

  if (navigator.appName == "Microsoft Internet Explorer"){
    alert("OnStyle currently does not support Internet Explorer :(");
    return false;
  }
  return true;
}

function getTotalHeight(element)
{
  if (!element.style) return;

  var count = 0;
  var height = parseInt(element.style.height);
  if (element.hasChildNodes()){
    var children = element.childNodes;
    for (var childIndex = 0; childIndex < children.length; childIndex++){
      if (children[childIndex].nodeName == "DIV" && isEditable( children[childIndex] ) != "" && children[childIndex].style){
        currentHeight = parseInt(children[childIndex].style.top) + parseInt(children[childIndex].style.height);
        if (currentHeight > height) height = currentHeight;
      }
    }
  }
  return height;
}

function isEditable(element)
{
  if (element != document && element.id != "" && element.id != osDialogID  && element.id != osEditorAreaID  && element.id != osOutputAreaID){
    return true;
  }
  return false;
}

function isDraggable(element)
{
  if (element != document && element != container && element.id != ""  && element.id != osEditorAreaID  && element.id != osOutputAreaID && element.id != osEditorTitleID && element.id != osEditorID){
    return true;
  }
  return false;
}

function findObjectWithID(element)
{
  var context = element;
  while (context != document){
    if (context.nodeName && context.id){
      if (context.nodeName=="DIV" && context.id != osHighlightID){
        break;
      }
    }
    context = context.parentNode;
  }
  if (context == document){
    return null;
  }
  return context;
}



//
// Non-const methods
//
function populateRootOptions()
{
  var select = document.getElementById(osRootContainerID);
  if (!select){
    alert("UI error. Please contact the developer.");
    return;
  }

  var elements = document.getElementsByTagName("DIV");
  if (!elements) return false;
  for (elementIndex = 0; elementIndex < elements.length; elementIndex++){
    if (elements[elementIndex].id && isEditable(elements[elementIndex])){
      // Note: IE7 has a bug of not being able to edit innerHTML of select so do this:
      select.options[select.options.length] = new Option(elements[elementIndex].id, elements[elementIndex].id);
    }
  }  
}

function initializeDialog()
{
  if (dialog){
    removeEvent(dialog, "mousemove", update, false);
    removeEvent(dialog, "mousedown", grab, false);
    dialog = null;
  }

  dialog = document.getElementById(osDialogID);
  if (!dialog){
    alert("Initialization error: Dialog box not found.");
    return;
  }
  addEvent(dialog, "mousemove", update, false);
  addEvent(dialog, "mousedown", grab, false);
  addEvent(dialog, "mouseover", highlightOn, false);
  addEvent(dialog, "mouseout", highlightOff, false);

  update();
}

function initOnStyle(elementID, findAlternativeDiv)
{
  if (!browserSupported()) return;

  if (eventRoot){
    removeEvent(eventRoot, "mousemove", update, false);
    removeEvent(eventRoot, "mousedown", grab, false);
    removeEvent(eventRoot, "mouseover", highlightOn, false);
    removeEvent(eventRoot, "mouseout", highlightOff, false);
  }
  eventRoot = document;

  container = null;
  if (elementID){
    container = document.getElementById(elementID);
  }
  if (!container && findAlternativeDiv)
  {
    var elementList = document.getElementsByTagName('div');
    if (elementList.length > 0){
      container = elementList[0];
    }
  }
  if (!container){
    alert("Please set a correct root container ID from the dialog.");
    return;
  }

  eventRoot = container;
  container.style.zIndex = 0;
  
  display = document.getElementById(osRootContainerID);
  display.value = container.id;

  initializeElement(container);
  if (container.hasChildNodes()){
    var children = container.childNodes;
    for (var childIndex = 0; childIndex < children.length; childIndex++){
      if (children[childIndex].nodeName == "DIV" &&  isEditable( children[childIndex] )){
        initializeElement(children[childIndex]);
      }
    }
  }

  if (container.style){
    container.style.position = "relative";
    mouseOffsetY = parseInt(container.style.top);
    mouseOffsetX = parseInt(container.style.left);
    container.style.top = "0px";
    container.style.left = "0px";
    container.style.height = getTotalHeight(container) + "px";
  }

  addEvent(eventRoot, "mousemove", update, false);
  addEvent(eventRoot, "mousedown", grab, false);
  addEvent(eventRoot, "mouseover", highlightOn, false);
  addEvent(eventRoot, "mouseout", highlightOff, false);

  update();

  initializedOnce = true;
}

function changeRoot()
{
  newRootID = document.getElementById(osRootContainerID).value;
  if (newRootID){
    newContainer = document.getElementById(newRootID);
  }
  if (newContainer){
    var goahead = true;
    if (initializedOnce == true){
      goahead = confirm("Make sure you save the current edit before change root! Continue?");
    }
    if (goahead){
      initOnStyle(newRootID, false);
      return;
    }    
  }
  else{
    alert("Could not find such ID");
  }
  if (container){
    display = document.getElementById(osRootContainerID);
    display.value = container.id;
  }
}

function initializeElement(element)
{
  element.style.position = "absolute";
  element.style.top = element.offsetTop.toString() + "px";
  element.style.left = element.offsetLeft.toString() + "px";
  element.style.width = element.offsetWidth.toString() + "px";
  element.style.height = element.offsetHeight.toString() + "px";
}

function pushDownElement()
{
  if (!selectedObject) return;
  if (selectedObject.style){
    selectedObject.style.zIndex -= 1;
    if (selectedObject.style.zIndex < 1) selectedObject.style.zIndex = 1;
  }
}

function updateElementPositionAndSize()
{
  if (!selectedObject) return;
  if (selectedObject.style){
    var x = document.getElementById(osPosXID).value;
    var y = document.getElementById(osPosYID).value;
    var w = document.getElementById(osWidthID).value;
    var h = document.getElementById(osHeightID).value;
    selectedObject.style.top = y + "px";
    selectedObject.style.left = x + "px";
    selectedObject.style.width = w + "px";
    selectedObject.style.height = h + "px";
  }
}

function update(event)
{
  getMouseXY(event); // NS is passing (event), while IE is passing (null)

  if (!dragobj || dragobj != selectedObject) return;

  var osPosX = document.getElementById('osPosX');
  var osPosY = document.getElementById('osPosY');
  var osWidth = document.getElementById('osWidth');
  var osHeight = document.getElementById('osHeight');
  if (osPosX){
    osPosX.value = elex;
  }
  if (osPosY){
    osPosY.value = eley;
  }
  if (osWidth){
    osWidth.value = elew;
  }
  if (osHeight){
    osHeight.value = eleh;
  }

  updateEditor(selectedObject);
}

function highlightOn(event)
{
  var target = getEventTarget(event);
  if (!target) return;
  var context = findObjectWithID(target);
  if (!context || context == container) return;

  //
  // Highlight the selection
  //
  var highlight = document.getElementById(osHighlightID);
  if (!highlight && isEditable(context) ){
    context.innerHTML += "<img id=\""+ osHighlightImageID + "\" src=\""+osBGImageUrl+"\" style=\"position:absolute; top:0px; left:0px; width:100%;\" />";
    context.innerHTML += "<div id=\""+ osHighlightID + "\" style=\"position:absolute; top:0px; left:0px; width:100%; height:100%; background-color: Pink; /* for IE */ filter:alpha(opacity=50); opacity: 0.5; \">&nbsp;</div>";
    highlightedObject = context;
  }
  if (isDraggable(context)){
    objectInFocus = context;
  }
}

function highlightOff(event)
{
  var target = getEventTarget(event);
  if (!target) return;
  var context = findObjectWithID(target);
  if (!context || context == container) return;

  //
  // Turn off the highlight
  //
  var highlight = document.getElementById(osHighlightID);
  if (highlight){
    highlight.parentNode.removeChild(highlight);
  }
  highlight = document.getElementById(osEditButtonID);
  if (highlight){
    highlight.parentNode.removeChild(highlight);
  }
  highlight = document.getElementById(osHighlightImageID);
  if (highlight){
    highlight.parentNode.removeChild(highlight);
    if (context.style.zIndex == highestZIndexForElement){
      context.style.zIndex -= 1;
    }
  }
  highlightedObject = null;
}

function getMouseXY(event) // works on IE6,FF,Moz,Opera7
{ 
  if (!event) event = window.event; // works on IE, but not NS (we rely on NS passing us the event)

  if (event)
  { 
    if (event.pageX || event.pageY)
    { // this doesn't work on IE6!! (works on FF,Moz,Opera7)
      mousex = event.pageX;
      mousey = event.pageY;
      algor = '[event.pageX]';
      if (event.clientX || event.clientY) algor += ' [event.clientX] '
    }
    else if (event.clientX || event.clientY)
    { // works on IE6,FF,Moz,Opera7
      mousex = event.clientX + document.body.scrollLeft;
      mousey = event.clientY + document.body.scrollTop;
      algor = '[event.clientX]';
      if (event.pageX || event.pageY) algor += ' [event.pageX] '
    }  
  }
}


function grab(event)
{
  var target = getEventTarget(event);
  if (!target){
    if (objectInFocus != null){
      target = objectInFocus;
    }
    else{
      return;
    }
  }

  var context = findObjectWithID(target);
  if (!context) return;

  dragobj = context;
  if ( isEditable(dragobj) ){
    selectedObject = dragobj;
    var selectedID = document.getElementById(osSelectedID);
    selectedID.value = selectedObject.id;
    dragobj.style.zIndex = highestZIndexForElement;
  }

  if ( !isDraggable(context) ) return; // cannot drag the root container

  // Add mouse event for drag and drop
  removeEvent(dialog, "mousemove", update, false);
  addEvent(dialog, "mousemove", drag, false);
  addEvent(dialog, "mouseup", drop, false);

  removeEvent(eventRoot, "mousemove", update, false);
  addEvent(eventRoot, "mousemove", drag, false);
  addEvent(eventRoot, "mouseup", drop, false);

  // Detect two objects being clicked at the same time
  if (grabx == mousex && graby == mousey && context.id != prevContext.id){
	context = prevContext;
	dragobj = prevContext;
  }
  // Double clicked?
  else if (grabx == mousex && graby == mousey){
    // do nothing
  }

  prevContext = context;
  grabx = mousex;
  graby = mousey;

  elex = orix = dragobj.offsetLeft;
  eley = oriy = dragobj.offsetTop;
  elew = oriw = dragobj.offsetWidth;
  eleh = orih = dragobj.offsetHeight;

  if (grabx - elex < elew * 0.5 + mouseOffsetX){
    mode = 0;
    setCursor("move");
  }
  else if (elex + elew - grabx < elew * 0.5 + mouseOffsetX){
    mode = 1;
    setCursor("se-resize");
  }
  else{
    mode = -1;
  }

  update(event);
}

function drag(event) // parameter passing is important for NS family 
{
  if (dragobj)
  {
    elex = orix + (mousex - grabx);
    eley = oriy + (mousey - graby);
    elew = oriw + (mousex - grabx);
    eleh = orih + (mousey - graby);

    if (mode == 0){
      dragobj.style.position = "absolute";
      dragobj.style.left = (elex).toString(10) + 'px';
      dragobj.style.top  = (eley).toString(10) + 'px';
      dragobj.style.backgroundPosition = (20-elex).toString(10) + 'px '+ (20-eley).toString(10) + 'px';
    }
    else if (mode == 1 && dragobj == selectedObject){
      dragobj.style.width  = (elew).toString(10) + 'px';
      dragobj.style.height = (eleh).toString(10) + 'px';
    }

  }
  update(event);
  return false; // in IE this prevents cascading of events, thus text selection is disabled
}

function drop(event)
{
  update(event);

  removeEvent(dialog, "mousemove", drag, false);
  addEvent(dialog, "mousemove", update, false);

  removeEvent(eventRoot, "mousemove", drag, false);
  addEvent(eventRoot, "mousemove", update, false);

  setCursor("default");
  mode = -1;

  if (orix != elex || oriy != eley || oriw != elew || orih != eleh){
//    saveLayout();
  }
}

function getHtml(excludeStyle)
{
  if (!container) return;

  var console = document.getElementById(osOutputID);
  if (!console) return;
  console.value = "";

  var key = new RegExp("^((?!" + container.id + ").)*$", "img");
  var html = container.parentNode.innerHTML.replace(/>/img, ">\r\n");
  html = html.replace(key, "");

  html += container.innerHTML.replace(/>/img, ">\r\n");
  if (excludeStyle){
    html = html.replace(/(<div .*id=.*)style=\".*\"(.*)/img, "$1$2");
    html = html.replace(/(<div .*) style=\".*\"(.*id=.*)/img, "$1$2");
//    html = html.replace(/(<[a-zA-Z][a-zA-Z]*.*id=.*)style=\".*\"(.*)/img, "$1$2");
//    html = html.replace(/(<[a-zA-Z][a-zA-Z]*.*) style=\".*\"(.*id=.*)/img, "$1$2");
  }
  html += "</div>";
  html = html.replace(/\n/g, "");
  html = html.replace(/\r/g, "");
  html = html.replace(/div>/img, "div>\r\n");
  html = html.replace(/(<div .*>)/img, "$1\r\n"); // This is not working?

  console.value = html;
  showOutputArea();
}

function getCss()
{
  if (!container) return;

  var console = document.getElementById(osOutputID);
  if (!console) return;
  console.value = "";

  var key = new RegExp("^((?!" + container.id + ").)*$", "img");
  var value = container.parentNode.innerHTML.replace(/>/img, ">\r\n");
  value = value.replace(key, "");
  value = value.replace(/.*id=\"(.*)\".*style=\"(.*)\".*/img, "#$1{$2}"); // Chrome, Safari
  value = value.replace(/.*id=(.*) .*style=\"(.*)\".*/img, "#$1{$2}"); // ~IE7
  value = value.replace(/.*style=\"(.*)\".*id=(.*)[ >].*/img, "#$2{$1}"); // IE8
  value = value.replace(/\n/g, "");
  value = value.replace(/\r/g, "");
  console.value = value;

  css = container.innerHTML;
  css = css.replace(/>/img, ">\r\n");
  css = css.replace(/^((?!div).)*$/img, "");
  css = css.replace(/^((?!id=).)*$/img, "");
  css = css.replace(/^((?!style=).)*$/img, "");

  css = css.replace(/.*id=\"(.*)\".*style=\"(.*)\".*/img, "#$1{$2}"); // Chrome, Saferi
  css = css.replace(/.*id=(.*) .*style=\"(.*)\".*/img, "#$1{$2}"); // IE7
  css = css.replace(/.*style=\"(.*)\".*id=(.*)[ >].*/img, "#$2{$1}"); // IE8
  css = css.replace(/\n/g, "");
  css = css.replace(/\r/g, "");
  console.value += css;
  console.value = console.value.replace(/}/img, "}\r\n");

  showOutputArea();
}

function showOutputArea()
{
  var element = document.getElementById(osOutputAreaID);
  if (element){
    element.style.visibility = "visible";
    element.style.zIndex = highestZIndex;
  }
}

function hideOutputArea()
{
  var element = document.getElementById(osOutputAreaID);
  if (element){
    element.style.visibility = "hidden";
  }
}

function saveLayout()
{
  elem = document.getElementById("save_window");
  param = "id=" + dragobj.id;
  if (mode == 0){
    param += "&amp;left=" + (elex).toString(10);
    param += "&amp;top=" + (eley).toString(10);
  }
  if (mode == 1){
    param += "&amp;width=" + (elew).toString(10);
    param += "&amp;height=" + (eleh).toString(10);
  }
  elem.innerHTML = "<iframe src='save.php?" + param +"' style='visibility:hidden; border:none;'></iframe>";
}
